home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / umich / network / ka9q / ka9q_src.arc / SMTPCLI.C < prev    next >
C/C++ Source or Header  |  1988-07-28  |  17KB  |  791 lines

  1. /* smtpcli.c
  2.  *    Client routines for Simple Mail Transfer Protocol ala RFC821
  3.  *    A.D. Barksdale Garbee II, aka Bdale, N3EUA
  4.  *    Copyright 1986 Bdale Garbee, All Rights Reserved.
  5.  *    Permission granted for non-commercial copying and use, provided
  6.  *    this notice is retained.
  7.  *    Modified 14 June 1987 by P. Karn for symbolic target addresses,
  8.  *    also rebuilt locking mechanism
  9.  *    Limit on max simultaneous sessions, reuse of connections - 12/87 NN2Z
  10.  */
  11. #include <stdio.h>
  12. #if (!ATARI_ST || LATTICE)    /* DG2KK */
  13. #include <fcntl.h>
  14. #endif
  15. #include "global.h"
  16. #include "netuser.h"
  17. #include "mbuf.h"
  18. #include "timer.h"
  19. #include "tcp.h"
  20. #include "smtp.h"
  21. #include "trace.h"
  22. #include "cmdparse.h"
  23.  
  24. extern int16 lport;            /* local port placeholder */
  25. extern int32 resolve();
  26. static struct timer smtpcli_t;
  27. int32 gateway;
  28.  
  29. #ifdef SMTPTRACE
  30. int16    smtptrace = 0;            /* used for trace level */
  31. int dosmtptrace();
  32. #endif
  33.  
  34. int16    smtpmaxcli  = MAXSESSIONS;    /* the max client connections allowed */
  35. int16    smtpcli = 0;            /* number of client connections
  36.                     * currently open */
  37.  
  38. static struct smtp_cb *cli_session[MAXSESSIONS]; /* queue of client sessions  */
  39.  
  40. int dosmtptick(),dogateway(),dosmtpmaxcli(),mlock(),dotimer();
  41. void quit(),abort_trans(),rejextjob(),sendit(),del_session(),del_job();
  42. void rejectjob(),execjobs(),smtp_transaction();
  43. struct smtp_cb *newcb(),*lookup();
  44. struct smtp_job *setupjob();
  45.  
  46. struct cmds smtpcmds[] = {
  47.     "gateway",    dogateway,    0,    NULLCHAR,    NULLCHAR,
  48.     "kick",     dosmtptick,    0,    NULLCHAR,    NULLCHAR,
  49.     "maxclients",    dosmtpmaxcli,    0,    NULLCHAR,    NULLCHAR,
  50.     "timer",    dotimer,    0,    NULLCHAR,    NULLCHAR,
  51. #ifdef SMTPTRACE
  52.     "trace",    dosmtptrace,    0,    NULLCHAR,    NULLCHAR,
  53. #endif
  54.     NULLCHAR,    NULLFP,     0,    
  55.     "subcommands: gateway kick maxclients timer trace",
  56.         NULLCHAR,
  57. };
  58.  
  59. dosmtp(argc,argv)
  60. int argc;
  61. char *argv[];
  62. {
  63.     return subcmd(smtpcmds,argc,argv);
  64. }
  65.  
  66. static int
  67. dosmtpmaxcli(argc,argv)
  68. int argc;
  69. char *argv[];
  70. {
  71.     int x;
  72.     if (argc < 2)
  73.         printf("%d\n",smtpmaxcli);
  74.     else {
  75.         x = atoi(argv[1]);
  76.         if (x > MAXSESSIONS)
  77.             printf("max clients must be <= %d\n",MAXSESSIONS);
  78.         else
  79.             smtpmaxcli = x;
  80.     }
  81.     return 0;
  82. }
  83.  
  84. static int
  85. dogateway(argc,argv)
  86. int argc;
  87. char *argv[];
  88. {
  89.     char *inet_ntoa();
  90.     int32 n;
  91.     extern char badhost[];
  92.  
  93.     if(argc < 2){
  94.         printf("%s\n",inet_ntoa(gateway));
  95.     } else if((n = resolve(argv[1])) == 0){
  96.         printf(badhost,argv[1]);
  97.         return 1;
  98.     } else
  99.         gateway = n;
  100.     return 0;
  101. }
  102.  
  103. #ifdef SMTPTRACE
  104. static int
  105. dosmtptrace(argc,argv)
  106. int argc;
  107. char *argv[];
  108. {
  109.     if (argc < 2)
  110.         printf("%d\n",smtptrace);
  111.     else 
  112.         smtptrace = atoi(argv[1]);
  113.     return 0;
  114. }
  115. #endif
  116.  
  117. /* Set outbound spool poll interval */
  118. static int
  119. dotimer(argc,argv)
  120. int argc;
  121. char *argv[];
  122. {
  123.     int dosmtptick();
  124.  
  125.     if(argc < 2){
  126.         printf("%d/%d\n",smtpcli_t.start - smtpcli_t.count,
  127.         smtpcli_t.start);
  128.         return 0;
  129.     }
  130.     smtpcli_t.func = (void (*)())dosmtptick;/* what to call on timeout */
  131.     smtpcli_t.arg = NULLCHAR;        /* dummy value */
  132.     smtpcli_t.start = atoi(argv[1]);    /* set timer duration */
  133.     start_timer(&smtpcli_t);        /* and fire it up */
  134.     return 0;
  135. }
  136.  
  137. /* this is the routine that gets called every so often to do outgoing mail
  138.    processing */
  139. int
  140. dosmtptick()
  141. {
  142.     register struct smtp_cb *cb;
  143.     char    tmpstring[LINELEN], wfilename[13], prefix[9];
  144.     char    from[LINELEN], to[LINELEN];
  145.     char *cp, *cp1;
  146.     int32 destaddr;
  147.     FILE *wfile;
  148.  
  149. #ifdef SMTPTRACE
  150.     if (smtptrace > 5) {
  151.         printf("smtp daemon entered\n");
  152.         fflush(stdout);
  153.     }
  154. #endif
  155.     for(filedir(mailqueue,0,wfilename);wfilename[0] != '\0';
  156.         filedir(mailqueue,1,wfilename)){
  157.  
  158.         /* save the prefix of the file name which it job id */
  159.         cp = wfilename;
  160.         cp1 = prefix;
  161.         while (*cp && *cp != '.')
  162.             *cp1++ = *cp++;
  163.         *cp1 = '\0';
  164.  
  165.         /* lock this file from the smtp daemon */
  166.         if (mlock(mailqdir,prefix))
  167.             continue;
  168.  
  169.         sprintf(tmpstring,"%s%s",mailqdir,wfilename);
  170.         if ((wfile = fopen(tmpstring,"r")) == NULLFILE) {
  171.             /* probably too many open files */
  172.             (void) rmlock(mailqdir,prefix);
  173.             /* continue to next message. The failure
  174.             * may be temporary */
  175.             continue;
  176.         }
  177.  
  178.         fgets(tmpstring,LINELEN,wfile); /* read target host */
  179.         rip(tmpstring);
  180.         fgets(from,LINELEN,wfile);    /* read target host */
  181.         rip(from);
  182.         fgets(to,LINELEN,wfile);    /* read target user */
  183.         rip(to);
  184.         fclose(wfile);
  185.  
  186.         if ((destaddr = mailroute(tmpstring)) == 0) {
  187.             printf("** smtpcli: Unknown address %s\n",tmpstring);
  188.             fflush(stdout);
  189.             (void) rmlock(mailqdir,prefix);
  190.             continue;
  191.         }
  192.  
  193.         if ((cb = lookup(destaddr)) == NULLCB) {
  194.             /* there are enough processes running already */
  195.             if (smtpcli >= smtpmaxcli) {
  196. #ifdef SMTPTRACE
  197.                 if (smtptrace) {
  198.                     printf("smtp daemon: too many processes\n");
  199.                     fflush(stdout);
  200.                 }
  201. #endif
  202.                     
  203.                 (void) rmlock(mailqdir,prefix);
  204.                 break;
  205.             }
  206.             if ((cb = newcb()) == NULLCB) {
  207.                 (void) rmlock(mailqdir,prefix);
  208.                 break;
  209.             } 
  210.             cb->ipaddr = destaddr;
  211.         } else {
  212.             /* This system is already is sending mail lets not
  213.             * interfere with its send queue.
  214.             */
  215.             if (cb->state != CLI_IDLE) {
  216.                 (void) rmlock(mailqdir,prefix);
  217.                 continue;
  218.             }
  219.         }
  220. #ifdef SMTPTRACE
  221.         if (smtptrace > 1) {
  222.             printf("queue job %s To: %s From: %s\n",prefix,to,from);
  223.             fflush(stdout);
  224.         }
  225. #endif
  226.  
  227.         if (setupjob(cb,prefix,to,from) == NULLJOB) {
  228.             (void) rmlock(mailqdir,prefix);
  229.             del_session(cb);
  230.             break;
  231.         }
  232.     }
  233.  
  234.     /* start sending that mail */
  235.     execjobs();
  236.  
  237.     /* Restart timer */
  238.     start_timer(&smtpcli_t);
  239. #ifdef SMTPTRACE
  240.     if (smtptrace > 5) {
  241.         printf("smtp daemon done\n");
  242.         fflush(stdout);
  243.     }
  244. #endif
  245. }
  246.  
  247. /* this is the master state machine that handles a single SMTP transaction */
  248. void
  249. smtp_transaction(cb)
  250. struct smtp_cb *cb;
  251. {
  252.     void smtp_cts();
  253.     char reply;
  254.     int rcode;
  255.  
  256. #ifdef SMTPTRACE
  257.     if (smtptrace > 7) 
  258.         printf("smtp_transaction() enter state=%u\n",cb->state);
  259.     if (smtptrace) {
  260.         printf("%s\n",cb->buf);
  261.         fflush(stdout);
  262.     }
  263. #endif
  264.     /* Another line follows; ignore this one */
  265.     if(cb->buf[0] == '0' || cb->buf[3] == '-')
  266.         return;
  267.  
  268.     reply = cb->buf[0];
  269.     rcode = atoi(cb->buf);
  270.  
  271.     /* if service shuting down */
  272.     if (rcode == 421) {
  273.         quit(cb);
  274.         return;
  275.     }
  276.  
  277.     switch(cb->state) {
  278.     case CLI_OPEN_STATE:
  279.         if (reply != '2')
  280.             quit(cb);
  281.         else {
  282.             cb->state = CLI_HELO_STATE;
  283.             sendit(cb,"HELO %s\r\n",hostname);
  284.         }
  285.         break;
  286.     case CLI_HELO_STATE:
  287.         if (reply != '2')
  288.             quit(cb);
  289.         else {
  290.             cb->state = CLI_MAIL_STATE;
  291.             /* send both to speed things up */
  292.             sendit(cb,"MAIL FROM:<%s>\r\nRCPT TO:<%s>\r\n",
  293.                 cb->jobq->from,cb->jobq->to);
  294.         }
  295.         break;            
  296.     case CLI_MAIL_STATE:
  297.         if (reply != '2')
  298.             quit(cb);
  299.         else {
  300.             cb->state = CLI_RCPT_STATE;
  301.             /* the RCPT is sent already */
  302.         }
  303.         break;
  304.     case CLI_RCPT_STATE:
  305.         if (reply == '5') {
  306.             rejectjob(cb);
  307.             abort_trans(cb);
  308.         } else if (reply != '2')
  309.             abort_trans(cb);
  310.         else {
  311.             /* open text file here because it will be too
  312.             * late to abort in the data state.
  313.             */
  314.             /* if this file open fails abort */
  315.             if ((cb->tfile = fopen(cb->tname,"r")) == NULLFILE)
  316.                 abort_trans(cb);
  317.             else {
  318.                 cb->state = CLI_DATA_STATE;
  319.                 sendit(cb,"DATA\r\n");
  320.             }
  321.         }
  322.         break;
  323.     case CLI_DATA_STATE:
  324.         if (reply != '3')
  325.             abort_trans(cb);
  326.         else {
  327.             cb->state = CLI_SEND_STATE;
  328.             /* Kick the data transfer to get it started */
  329.             smtp_cts(cb->tcb,cb->tcb->window - cb->tcb->sndcnt);
  330.         }
  331.         break;
  332.     case CLI_SEND_STATE:
  333.         /* the transmitter upcall routine will advance the
  334.            state pointer on end of file, so we do nada... */
  335.         break;
  336.     case CLI_UNLK_STATE:
  337.         if (reply == '5') {
  338.             rejectjob(cb);
  339.             abort_trans(cb);
  340.         } else if (reply != '2')
  341.             abort_trans(cb);
  342.         else {
  343.             unlink(cb->wname);    /* unlink workfile */
  344.             /* close and unlink the textfile */
  345.             if(cb->tfile != NULLFILE) {
  346.                 fclose(cb->tfile);
  347.                 cb->tfile = NULLFILE;
  348.             }
  349.             unlink(cb->tname);
  350.             abort_trans(cb);
  351.         }
  352.         break;
  353.     case CLI_QUIT_STATE:
  354.         close_tcp(cb->tcb); /* close up connection */
  355.         break;
  356.     }
  357. }
  358.  
  359. /* abort the currrent job. Remove the lockfile.
  360.  * If more work exists set up the next job if
  361.  * not then shut down.
  362. */
  363. static void
  364. abort_trans(cb)
  365. struct smtp_cb *cb;
  366. {
  367.     if(cb->tfile != NULLFILE) {
  368.         fclose(cb->tfile);
  369.         cb->tfile = NULLFILE;
  370.     }
  371.     (void) rmlock(mailqdir,cb->jobq->jobname);
  372.     if (nextjob(cb)) {
  373.         sendit(cb,"RSET\r\n");
  374.         cb->state = CLI_HELO_STATE;
  375.     } else {
  376.         sendit(cb,"